#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#include "ring_buffer.h"

static bool is_power_of_2(uint32 n);
static uint32 roundup_power_of_2(uint32 a);
static struct ring_buffer *ring_buffer_init(char *buffer, uint32 size);

/* 初始化缓冲区 */
static struct ring_buffer *ring_buffer_init(char *buffer, uint32 size)
{
    struct ring_buffer *p_ring_buffer;
    int ret = 0;
    
    /* 申请缓冲区的内存 */
    p_ring_buffer = (struct ring_buffer *)malloc(sizeof(struct ring_buffer));
    if (!p_ring_buffer)
        return NULL;

    p_ring_buffer->buffer = buffer;
    p_ring_buffer->size = size;
    p_ring_buffer->in = 0;
    p_ring_buffer->out = 0;

    ret = pthread_mutex_init(&p_ring_buffer->mutex, NULL);
    if (ret != 0) {
        free(p_ring_buffer);
        return NULL;
    }

    sem_init(&p_ring_buffer->sem, 0, 0);

    return p_ring_buffer;
}

/* 申请缓冲区的内存 */
struct ring_buffer *ring_buffer_alloc(uint32 size)
{
    char *buffer;
    struct ring_buffer *ret;
 /*
 * round up to the next power of 2, since our 'let the indices
 * wrap' tachnique works only in this case.
 */
    if(!is_power_of_2(size))
        size = roundup_power_of_2(size);
 
    buffer = (char *)malloc(size);
    if (!buffer)
        return NULL;
 
    ret = ring_buffer_init(buffer, size);
    if (!ret)
        free(buffer);
 
    return ret;
}

/* 释放缓冲区的内存 */
void ring_buffer_free(struct ring_buffer *p_ring_buffer) 
{
    if (p_ring_buffer) {
        if (p_ring_buffer->buffer)
            free(p_ring_buffer->buffer);
        free(p_ring_buffer);
    }
}

/*将数据写入缓冲区*/
uint32 ring_buffer_put(struct ring_buffer *p_ring_buffer, char *buffer, uint32 len)
{
    uint32 l = 0;

    if (len > (p_ring_buffer->size - p_ring_buffer->in + p_ring_buffer->out))
        return 0;
    pthread_mutex_lock(&p_ring_buffer->mutex);

    if (p_ring_buffer->size > p_ring_buffer->in + len) {
        memcpy(p_ring_buffer->buffer + p_ring_buffer->in, buffer, len);
        p_ring_buffer->in += len;
    } else {
        l = p_ring_buffer->size - p_ring_buffer->in;
        memcpy(p_ring_buffer->buffer + p_ring_buffer->in, buffer, l);
        memcpy(p_ring_buffer->buffer, buffer + l, len - l);
        p_ring_buffer->in = len - l;
    }
    pthread_mutex_unlock(&p_ring_buffer->mutex);
    /*有数据放入缓冲区，信号量+1*/
    sem_post(&p_ring_buffer->sem);

    return len;
}

/*将数据从缓冲区读出来*/
uint32 ring_buffer_get(struct ring_buffer *p_ring_buffer, char *buffer, uint32 len)
{
    uint32 l;
    
    /*如果没数据则阻塞在这里*/
    sem_wait(&p_ring_buffer->sem);
    pthread_mutex_lock(&p_ring_buffer->mutex);
    
    if (p_ring_buffer->in > p_ring_buffer->out) {
        memcpy(buffer, p_ring_buffer->buffer + p_ring_buffer->out, len);
        p_ring_buffer->out += len;
    } else if (p_ring_buffer->out + len < p_ring_buffer->size) {
        memcpy(buffer, p_ring_buffer->buffer + p_ring_buffer->out, len);
        p_ring_buffer->out += len;
    } else {
        l = p_ring_buffer->size - p_ring_buffer->out;
        memcpy(buffer, p_ring_buffer->buffer + p_ring_buffer->out, l);
        memcpy(buffer + l, p_ring_buffer->buffer, len -l);
        p_ring_buffer->out = len - l;
    }

    pthread_mutex_unlock(&p_ring_buffer->mutex);

    return len;
}

/*判断n是否为2的幂*/
static bool is_power_of_2(uint32 n)
{
    return (n != 0 && ((n & (n - 1)) == 0));
}

/*将数字a向上取整为2的次幂*/
static uint32 roundup_power_of_2(uint32 a)
{
    int count = 0;
    uint32 position = 0;

    if (a == 0)
        return 0;

    for (count = a; count != 0; count >>= 1)
        position++;

    return (uint32)(1 << position);
}

